package com.ssy.lingxi.contract.serviceimpl;

import cn.hutool.core.date.DateUtil;
import com.ssy.lingxi.common.constant.contract.ContractSourceTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.contract.entity.ContractDO;
import com.ssy.lingxi.contract.model.constant.ContractOuterStatusEnum;
import com.ssy.lingxi.contract.model.vo.common.response.ContractPayPlanVO;
import com.ssy.lingxi.contract.model.vo.common.response.PageItemVO;
import com.ssy.lingxi.contract.model.vo.execute.request.ContractExecutePartyAPageVO;
import com.ssy.lingxi.contract.model.vo.execute.request.ContractExecutePartyBPageVO;
import com.ssy.lingxi.contract.model.vo.execute.response.ContractExecuteBasicsVO;
import com.ssy.lingxi.contract.model.vo.execute.response.ContractExecuteDetailVO;
import com.ssy.lingxi.contract.model.vo.execute.response.ContractExecuteQueryVO;
import com.ssy.lingxi.contract.repository.ContractRepository;
import com.ssy.lingxi.contract.service.IContractExecuteService;
import com.ssy.lingxi.contract.service.IContractPayPlanService;
import com.ssy.lingxi.contract.service.IFeignService;
import com.ssy.lingxi.dto.request.ApplyAmountDetailTotalSunQueryVO;
import com.ssy.lingxi.dto.response.ApplyAmountDetailTotalSunVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 合同执行接口实现
 * @author 伍将
 * @date 2021/2/2
 * @version 2.0.0
 */
@Service
public class ContractExecuteServiceImpl implements IContractExecuteService {

    @Resource
    private ContractRepository repository;

    @Resource
    private IContractPayPlanService payPlanService;

    @Resource
    private IFeignService feignService;

    /**
     * 甲方分页查询合同列表
     * @author 伍将
     * @date 2021/2/2
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractExecuteQueryVO>> pageListByPartyA(UserLoginCacheDTO user, ContractExecutePartyAPageVO pageVO) {

        List<Integer> outerStatusList = new ArrayList<>();
        outerStatusList.add(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getCode());
        outerStatusList.add(ContractOuterStatusEnum.INVALID.getCode());
        outerStatusList.add(ContractOuterStatusEnum.STOP_USING.getCode());
        outerStatusList.add(ContractOuterStatusEnum.EXPIRE.getCode());

        // 组装查询条件
        Specification<ContractDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("partyAMemberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("partyARoleId").as(Long.class), user.getMemberRoleId()));
            if (!ContractOuterStatusEnum.ALL.getCode().equals(pageVO.getOuterStatus())) {
                list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), pageVO.getOuterStatus()));
            } else {
                list.add(criteriaBuilder.in(root.get("outerStatus")).value(outerStatusList));
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThan(root.get("startTime").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThan(root.get("endTime").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getContractNo())) {
                list.add(criteriaBuilder.like(root.get("contractNo").as(String.class), "%" + pageVO.getContractNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getContractAbstract())) {
                list.add(criteriaBuilder.like(root.get("contractAbstract").as(String.class), "%" + pageVO.getContractAbstract().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getPartyBName())) {
                list.add(criteriaBuilder.like(root.get("partyBName").as(String.class), "%" + pageVO.getPartyBName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("startTime").descending());

        Page<ContractDO> result = repository.findAll(spec, page);
        return Wrapper.success(new PageData<>(result.getTotalElements(), convertContractExecuteQueryVO(result.getContent())));
    }

    /**
     * 乙方分页查询合同列表
     * @author 伍将
     * @date 2021/2/2
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ContractExecuteQueryVO>> pageListByPartyB(UserLoginCacheDTO user, ContractExecutePartyBPageVO pageVO) {
        List<Integer> outerStatusList = new ArrayList<>();
        outerStatusList.add(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getCode());
        outerStatusList.add(ContractOuterStatusEnum.STOP_USING.getCode());
        outerStatusList.add(ContractOuterStatusEnum.EXPIRE.getCode());

        // 组装查询条件
        Specification<ContractDO> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("partyBMemberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("partyBRoleId").as(Long.class), user.getMemberRoleId()));
            if (!ContractOuterStatusEnum.ALL.getCode().equals(pageVO.getOuterStatus())) {
                list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), pageVO.getOuterStatus()));
            } else {
                list.add(criteriaBuilder.in(root.get("outerStatus")).value(outerStatusList));
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThan(root.get("startTime").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThan(root.get("endTime").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getContractNo())) {
                list.add(criteriaBuilder.like(root.get("contractNo").as(String.class), "%" + pageVO.getContractNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getContractAbstract())) {
                list.add(criteriaBuilder.like(root.get("contractAbstract").as(String.class), "%" + pageVO.getContractAbstract().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getPartyAName())) {
                list.add(criteriaBuilder.like(root.get("partyAName").as(String.class), "%" + pageVO.getPartyAName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("startTime").descending());

        Page<ContractDO> result = repository.findAll(spec, page);
        return Wrapper.success(new PageData<>(result.getTotalElements(), convertContractExecuteQueryVO(result.getContent())));
    }

    /**
     * 转换执行合同返回VO
     * @author 伍将
     * @date 2021/2/2
     * @param contractList: 合同列表
     * @return 操作结果
     **/
    private List<ContractExecuteQueryVO> convertContractExecuteQueryVO(List<ContractDO> contractList) {
        // step1: 查询结算服务请款使用请款
        List<Long> contractIds = contractList.stream().map(ContractDO::getId).collect(Collectors.toList());
        List<ApplyAmountDetailTotalSunVO> helpList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(contractIds)) {
            ApplyAmountDetailTotalSunQueryVO queryVO = new ApplyAmountDetailTotalSunQueryVO();
            queryVO.setContractIds(contractIds);
            Wrapper<List<ApplyAmountDetailTotalSunVO>> helpWrapper =  feignService.pageContractExecuteDetailSum(queryVO);
            if (helpWrapper.getCode() == ResponseCode.SUCCESS.getCode()) {
                helpList.addAll(helpWrapper.getData());
            }
        }
        return contractList.stream().map(o -> {
            ContractExecuteQueryVO entity = new ContractExecuteQueryVO();
            entity.setId(o.getId());
            entity.setContractNo(o.getContractNo());
            entity.setContractAbstract(o.getContractAbstract());
            entity.setStartTime(DateUtil.format(DateUtil.date(o.getStartTime()), "yyyy-MM-dd"));
            entity.setEndTime(DateUtil.format(DateUtil.date(o.getEndTime()), "yyyy-MM-dd"));
            entity.setPartyAName(o.getPartyAName());
            entity.setPartyBName(o.getPartyBName());
            entity.setTotalAmount(o.getTotalAmount());
            entity.setExecuteAmount(o.getExecuteAmount());
            Optional<ApplyAmountDetailTotalSunVO> help = helpList.stream().filter(f -> Objects.equals(f.getContractId(), o.getId())).findFirst();
            BigDecimal payAmount = help.map(ApplyAmountDetailTotalSunVO::getPayAmount).orElse(BigDecimal.ZERO);
            entity.setPayAmount(payAmount.doubleValue());
            BigDecimal unPayApplyAmount=help.map(ApplyAmountDetailTotalSunVO::getUnPayApplyAmount).orElse(BigDecimal.ZERO);
            entity.setUnPayApplyAmount(unPayApplyAmount.doubleValue());
            BigDecimal unApplyAmount = BigDecimal.valueOf(o.getExecuteAmount()).subtract(payAmount).subtract(unPayApplyAmount).setScale(2, RoundingMode.HALF_UP);
            entity.setUnApplyAmount(unApplyAmount.doubleValue());
            entity.setOuterStatus(o.getOuterStatus());
            entity.setOuterStatusName(ContractOuterStatusEnum.getMessage(o.getOuterStatus()));
            return entity;
        }).collect(Collectors.toList());
    }

    /**
     * 获取外部状态列表
     * @author 伍将
     * @date 2021/2/2
     * @return 操作结果
     **/
    @Override
    public Wrapper<List<PageItemVO>> getOuterStatusList() {

        List<PageItemVO> resultList = new ArrayList<>();
        PageItemVO item = new PageItemVO();
        item.setStatus(ContractOuterStatusEnum.ALL.getCode());
        item.setName(ContractOuterStatusEnum.ALL.getMessage());
        resultList.add(item);
        item = new PageItemVO();
        item.setStatus(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getCode());
        item.setName(ContractOuterStatusEnum.COMPLETE_SIGN_CONTRACT.getMessage());
        resultList.add(item);
        item = new PageItemVO();
        item.setStatus(ContractOuterStatusEnum.STOP_USING.getCode());
        item.setName(ContractOuterStatusEnum.STOP_USING.getMessage());
        resultList.add(item);
        item = new PageItemVO();
        item.setStatus(ContractOuterStatusEnum.EXPIRE.getCode());
        item.setName(ContractOuterStatusEnum.EXPIRE.getMessage());
        resultList.add(item);

        return Wrapper.success(resultList);
    }

    /**
     * 获取合同详情
     * @author 伍将
     * @date 2021/3/9
     * @param user: 当前登录用户
     * @param contractId: 合同id
     * @return 操作结果
     **/
    @Override
    public Wrapper<ContractExecuteDetailVO> getDetail(UserLoginCacheDTO user, Long contractId) {

        ContractExecuteDetailVO result = new ContractExecuteDetailVO();

        ContractDO contract = repository.findById(contractId).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }

        // 获取合同基本信息
        ContractExecuteBasicsVO basics = new ContractExecuteBasicsVO();
        basics.setId(contractId);
        basics.setContractNo(contract.getContractNo());
        basics.setOuterStatus(contract.getOuterStatus());
        basics.setOuterStatusName(ContractOuterStatusEnum.getMessage(contract.getOuterStatus()));
        basics.setContractAbstract(contract.getContractAbstract());
        basics.setSourceType(contract.getSourceType());
        basics.setSourceTypeName(ContractSourceTypeEnum.getNameByCode(contract.getSourceType()));
        basics.setSourceId(contract.getSourceId());
        basics.setSourceNo(contract.getSourceNo());
        basics.setPartyAName(contract.getPartyAName());
        basics.setPartyBName(contract.getPartyBName());
        basics.setTotalAmount(contract.getTotalAmount());
        basics.setStartTime(DateUtil.format(DateUtil.date(contract.getStartTime()), "yyyy-MM-dd"));
        basics.setEndTime(DateUtil.format(DateUtil.date(contract.getEndTime()), "yyyy-MM-dd"));
        basics.setTurn(contract.getTurn());
        result.setBasics(basics);

        // 获取支付计划
        Wrapper<List<ContractPayPlanVO>> payPlanListWrapper = payPlanService.getPayPlanList(contractId);
        if (null == payPlanListWrapper || payPlanListWrapper.getCode() != ResponseCode.SUCCESS.getCode()) {
            throw new BusinessException(ResponseCode.CONTRACT_GET_PAY_PLAN_ERROR);
        }
        result.setPayPlanList(payPlanListWrapper.getData());

        return Wrapper.success(result);
    }
}
